package ar.edu.uade.centroDistribucion.sessionBeans;


import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import java.util.*;

import ar.edu.uade.centroDistribucion.entities.Articulo;
import ar.edu.uade.centroDistribucion.entities.EnvioATienda;
import ar.edu.uade.centroDistribucion.entities.ItemEnvioATienda;
import ar.edu.uade.centroDistribucion.entities.Tienda;
import ar.edu.uade.centroDistribucion.sessionBeans.administradorEnvioATienda;
import ar.edu.uade.centroDistribucion.valueObjects.EnvTVO;
import ar.edu.uade.centroDistribucion.valueObjects.EnvioPendienteResultadoVO;
import ar.edu.uade.centroDistribucion.valueObjects.NuevoArticuloVO;
import ar.edu.uade.centroDistribucion.valueObjects.VistaEnvTPendienteVO;
import ar.edu.uade.centroDistribucion.valueObjects.VistaEnvTVO;

public @Stateless class administradorEnvioATiendaBean implements administradorEnvioATienda {
	
	@PersistenceContext(unitName="CentroDistribucionTortuguitas")
	private EntityManager manager;
	
	@EJB
	private administradorArticulo adminArticulo;
	
	@SuppressWarnings("unchecked")

	//cargo los datos en VistaEnvTVO para ser mostrados en pantalla

	public List<VistaEnvTVO> iniciarEnvioATienda() {
		List<VistaEnvTVO> lvEnvT = null;
		VistaEnvTVO vEnvT = null;
		List envTsNuevos = null;
		EnvioATienda envio = null;
		try {
			//consulta a la base por los envt con estado nuevo 
			Query q= manager.createQuery("FROM EnvioATienda WHERE estado = 'Nuevo' ");
			
			envTsNuevos = q.getResultList();
			lvEnvT= new ArrayList<VistaEnvTVO>();
			for (Object object : envTsNuevos) {
				envio = (EnvioATienda)object;
				for (ItemEnvioATienda item : envio.getItems()) {
					vEnvT = new VistaEnvTVO();
					vEnvT.setArticulo(item.getArticulo().getReferencia());
					vEnvT.setDescripcion(item.getArticulo().getDescripcion());
					vEnvT.setCantAEnviar(item.getCantidad());
					vEnvT.setEnvioATiendaId(envio.getId());
					vEnvT.setTiendaId(envio.getTienda().getId());
					lvEnvT.add(vEnvT);
				}
			}			
		} catch (Exception e) {
			// TODO: handle exception
			System.out.print("Error: " + e.getMessage() + e.getStackTrace());
			return null;			
		}		
		return lvEnvT;
	}
	
	//Cargo los datos en EnvTVO y lo grabo en la base
	public void Generar(EnvTVO envTVO,int idEnvioATienda) {
	//Actualiza el estado de los envts y actualiza el stock de los articulos
		EnvioATienda envio = null;				
		Query q =manager.createQuery("SELECT envt FROM EnvioATienda envt WHERE envt.id = :param");
		q.setParameter("param", idEnvioATienda);
		envio = (EnvioATienda)q.getSingleResult();
		for (ItemEnvioATienda item : envio.getItems()) {
			item.setEstado("Generado");
			adminArticulo.ConfirmarEnvio(item.getArticulo().getId(),item.getCantidad());				
		}
		envio.setEstado("Generado");
		manager.merge(envio);

	}	
	
	//este metodo es llamado una vez que se procesaron los repaf
	@SuppressWarnings("unchecked")
	public void revisarPendientes() {
		//reviso los EnvT pendientes
		//si de esos pendientes puedo cumplir el pedido genero EnvT nuevos
		EnvioATienda envT = null;
		int diferencia = 0;
		int stockReal = 0;
		List<ItemEnvioATienda> itemsAEnviar = null;
		ItemEnvioATienda itemEnvTNuevo = null;
		EnvioATienda envTNuevo = null; 
		Query q = manager.createQuery("SELECT envt FROM EnvioATienda envt WHERE envt.estado = 'Pendiente' ORDER BY envt.id");
		List envTPendientes = q.getResultList();
		for (Object object : envTPendientes) {
			envT = (EnvioATienda)object;
			itemsAEnviar = new ArrayList<ItemEnvioATienda>();
			//Reviso por item para crear envts con estado "Nuevo"
			for (ItemEnvioATienda item : envT.getItems()) {
				if (item.getEstado().equals("Pendiente")) {
					//Si puedo cumplir con lo que tengo todos los pedidos sigo, sino no
					if(cumploTodosLosPedidos(item))
					{
						//valido lo que hay para enviar
						stockReal = adminArticulo.ObtenerStockReal(item.getArticulo().getId());
						diferencia = stockReal - item.getCantidad();
						if (diferencia >=0) {
							//hay stock para este articulo, genero el evt item Nuevo y actualizo el estado del item de envt
							itemEnvTNuevo = new ItemEnvioATienda();
							itemEnvTNuevo.setArticulo(item.getArticulo());
							itemEnvTNuevo.setCantidad(item.getCantidad());
							itemEnvTNuevo.setEstado("Nuevo");
							itemsAEnviar.add(itemEnvTNuevo);
							adminArticulo.ActualizarStockComprometido(item.getArticulo().getId(), item.getCantidad());						
							item.setEstado("Generado");
					}
					/*else{
						//si hay algo de stock lo envio igual
						if (stockReal > 0) {
							itemEnvTNuevo = new ItemEnvioATienda();
							itemEnvTNuevo.setArticulo(item.getArticulo());
							//envio lo que queda
							itemEnvTNuevo.setCantidad(stockReal);
							itemEnvTNuevo.setEstado("Nuevo");
							itemsAEnviar.add(itemEnvTNuevo);
							adminArticulo.ActualizarStockComprometido(item.getArticulo().getId(), stockReal);
							//actualizo la cantidad pendiente y sigue pendiente
							item.setCantidad(item.getCantidad()- stockReal);
						}*/
						//si no hay stock no pasa nada
					}
				}
			}
			//si tengo algo en la lista de items a enviar genero un nuevo envt con estado Nuevo
			if (itemsAEnviar.size() > 0) {
				envTNuevo = new EnvioATienda();
				envTNuevo.setEstado("Nuevo");
				envTNuevo.setTienda(envT.getTienda());
				envTNuevo.setItems(itemsAEnviar);
				manager.persist(envTNuevo);
				for (ItemEnvioATienda itemEnvT : envTNuevo.getItems()) {
					itemEnvT.setEnvioATienda(envTNuevo);
				}
				//para que actualice las referencias
				manager.merge(envTNuevo);				
			}
			//finalmente grabo el EnvT pendiente y reviso el estado
			manager.merge(envT);
			revisarEstado(envT);
		}
	}

	private boolean cumploTodosLosPedidos(ItemEnvioATienda item) {
		// TODO Auto-generated method stub
		EnvioATienda envT = null;
		int cantidadPendienteTotal= 0;
						
		Query q = manager.createQuery("SELECT e FROM EnvioATienda e INNER JOIN e.items i INNER JOIN i.articulo" +
									" WHERE e.estado = 'Pendiente' AND i.estado = 'Pendiente' AND i.articulo.id = "+ item.getArticulo().getId()+
									" ORDER BY e.id");
		List envTPendientes = q.getResultList();
		
		for (Object object : envTPendientes) {
			envT = (EnvioATienda)object;
			for (ItemEnvioATienda itemEnvT : envT.getItems()) {
				if (itemEnvT.getEstado().equals("Pendiente") && itemEnvT.getArticulo().getId() == item.getArticulo().getId()) {
					cantidadPendienteTotal =+ itemEnvT.getCantidad();
				}				
			}			
		}
		
		if (adminArticulo.ObtenerStockReal(item.getArticulo().getId()) < cantidadPendienteTotal) {
			//no puedo completar todos los pedidos para ese articulo.
			return false;
		}else {
			return true;	
		}		
	}

	private void revisarEstado(EnvioATienda envT) {
		boolean todosGenerados = true;
		for (ItemEnvioATienda item : envT.getItems()) {
			if (item.getEstado().equals("Pendiente")) {
				todosGenerados = false;
			}
		}
		//Si todos estan cerrados elimino la envtpendiente porque ya deben estar sus envt nuevas creadas
		if(todosGenerados)
			manager.remove(envT);
		else
		{
			envT.setEstado("Pendiente");
			manager.merge(envT);
		}	
	}

	@SuppressWarnings("unchecked")
	public int pendientePorArticulo(int articuloId) {
		Query q = manager.createQuery("SELECT envt FROM EnvioATienda envt WHERE envt.estado = 'Pendiente'");
		List enviosPosibles = q.getResultList();
		EnvioATienda envt = null;
		int pendienteTotal = 0;
		for (Object object : enviosPosibles) {
			envt = (EnvioATienda)object;
			for (ItemEnvioATienda item : envt.getItems()) {
				if (item.getArticulo().getId()== articuloId) {
					pendienteTotal = pendienteTotal+ item.getCantidad();
				}
			}
		}
		return pendienteTotal;
	}
	
	public List<VistaEnvTPendienteVO> IniciarEnvioPendientes()
	{
		Query q = manager.createQuery("SELECT envt FROM EnvioATienda envt WHERE envt.estado = 'Pendiente'");
		List enviosPosibles = q.getResultList();
		EnvioATienda envt = null;
		List<VistaEnvTPendienteVO> lista = new ArrayList<VistaEnvTPendienteVO>();
		VistaEnvTPendienteVO vistaVO = null;
		for (Object object : enviosPosibles) {
			envt = (EnvioATienda)object;
			for (ItemEnvioATienda item : envt.getItems()) {
				if (item.getEstado().equals("Pendiente") && adminArticulo.ObtenerStockReal(item.getArticulo().getId())>0) {
					vistaVO = new VistaEnvTPendienteVO();
					vistaVO.setArticulo(item.getArticulo().getReferencia());
					vistaVO.setCantidadPedida(item.getCantidad());
					vistaVO.setDescripcion(item.getArticulo().getDescripcion());
					vistaVO.setEnvioTiendaId(envt.getId());
					vistaVO.setStockRealArticulo(adminArticulo.ObtenerStockReal(item.getArticulo().getId()));
					vistaVO.setTiendaId(envt.getTienda().getId());
					lista.add(vistaVO);
				}
			}
		}
		return lista;
	}
	
	private EnvioATienda obtener(int id)
	{
		EnvioATienda envio = null;
		Query q = manager.createQuery("FROM EnvioATienda e WHERE e.id="+id);
		envio = (EnvioATienda)q.getSingleResult();
		if (envio != null) {
			System.out.println("Envio encontrado");	
		}else {
			System.out.println("Envio NO encontrado");
		}
		
		return envio;
	}
	

	
	/*private void AgregarAEnvioNuevo(ItemEnvioATienda itemNuevo,int tiendaId)
	{
		EnvioATienda envio;
		boolean encontrado = false;
		//Busco los envios que tiene esta tienda y agrego el item, si no tiene creo uno nuevo para el item.
		Query q = manager.createQuery("FROM EnvioATienda e INNER JOIN e.tienda t WHERE e.estado = 'Nuevo' AND t.id="+tiendaId);
		System.out.println("AgregarAEnvioNuevo");
		if (q.getResultList().size() > 0) {
			envio = (EnvioATienda)q.getSingleResult();
			//Me fijo si ese articulo ya esta en la lista
			for (ItemEnvioATienda item : envio.getItems()) {
				if (item.getArticulo().getReferencia().equals(itemNuevo.getArticulo().getReferencia())) {
					//Lo encontre actualizo la cantidad entonces
					item.setCantidad(item.getCantidad()+itemNuevo.getCantidad());
					encontrado = true;
				}
			}
			if (!encontrado) {
				//No esta en la lista, lo agrego
				itemNuevo.setEnvioATienda(envio);
				envio.getItems().add(itemNuevo);				
			}
			//finalmente grabo ese envio
			manager.merge(envio);
		}else {
			//No hay envios, creo uno nuevo
			envio = new EnvioATienda();
			envio.setEstado("Nuevo");
			envio.setTienda(manager.find(Tienda.class,tiendaId));
			envio.getItems().add(itemNuevo);
			manager.persist(envio);
			//Problema de ids.....
			itemNuevo.setEnvioATienda(envio);
			manager.merge(envio);
		}
	}*/
	@SuppressWarnings("unchecked")
	private void AgregarAEnvioNuevo(ItemEnvioATienda itemNuevo,int tiendaId)
	 {
	  EnvioATienda envioActual;
	  List<EnvioATienda> lista=null;
	  boolean encontrado = false;
	  //Busco los envios que tiene esta tienda y agrego el item, si no tiene creo uno nuevo para el item.
	  Query q = manager.createQuery("FROM EnvioATienda e INNER JOIN e.tienda t WHERE e.estado = 'Nuevo' AND t.id="+tiendaId);
	  System.out.println("AgregarAEnvioNuevo");
	  lista = q.getResultList();
	  if (lista.size() > 0) {
	   //envio = (EnvioATienda)q.getSingleResult();
	    for (EnvioATienda envio : lista) {
	     //NUNCA deberia venir mas de 1!!
	     //Me fijo si ese articulo ya esta en la lista
	     for (ItemEnvioATienda item : envio.getItems()) {
	      if (item.getArticulo().getReferencia().equals(itemNuevo.getArticulo().getReferencia())) {
	       //Lo encontre actualizo la cantidad entonces
	       item.setCantidad(item.getCantidad()+itemNuevo.getCantidad());
	       encontrado = true;
	      }
	     }
	     if (!encontrado) {
	      //No esta en la lista, lo agrego
	      itemNuevo.setEnvioATienda(envio);
	      envio.getItems().add(itemNuevo);    
	     }
	     //finalmente grabo ese envio
	     manager.merge(envio); 
	     break;
	   }
	   
	  }else {
	   //No hay envios, creo uno nuevo
	   envioActual = new EnvioATienda();
	   envioActual.setEstado("Nuevo");
	   envioActual.setTienda(manager.find(Tienda.class,tiendaId));
	   envioActual.getItems().add(itemNuevo);
	   manager.persist(envioActual);
	   //Problema de ids.....
	   itemNuevo.setEnvioATienda(envioActual);
	   manager.merge(envioActual);
	  }
	 }
	
	//Lo que viene son los pedidos incompletos o no que se decidio enviar
	public void ProcesarEnviosPendientes(List<EnvioPendienteResultadoVO> lista)
	{
		EnvioATienda envio;
		ItemEnvioATienda itemNuevo;
		int diferencia;
		try {
			for (EnvioPendienteResultadoVO envioPendienteResultadoVO : lista) {
				if (envioPendienteResultadoVO.getCantidad()>0) {
					envio = obtener(envioPendienteResultadoVO.getEnvioId());
					for (ItemEnvioATienda item : envio.getItems()) {
						System.out.println("llegue al for :) "+envioPendienteResultadoVO.getReferencia());
						System.out.println("llegue al for2 :) "+item.getArticulo().getReferencia());
						if (item.getArticulo().getReferencia().equals(envioPendienteResultadoVO.getReferencia().trim())) {
							//Tengo el item a actualizar
							System.out.println("Tengo el item a actualizar");
							diferencia = item.getCantidad()- envioPendienteResultadoVO.getCantidad();
							//Creo el item nuevo a grabar
							
							itemNuevo = new ItemEnvioATienda();
							itemNuevo.setArticulo(adminArticulo.ObtenerPorReferencia(envioPendienteResultadoVO.getReferencia().trim()));
							itemNuevo.setCantidad(envioPendienteResultadoVO.getCantidad());
							itemNuevo.setEstado("Nuevo");
							
							//solo puede dar mayor a cero o cero nunca menor por la validacion en pantalla
							if (diferencia > 0) {
								//El item tengo que guardarlo con el resto y creo un item nuevo de ENVT
								item.setCantidad(diferencia);							
							}else {
								//Completo la cantidad de ese item lo pongo generado
								item.setCantidad(0);
								item.setEstado("Generado");
							}
							//Al item nuevo lo agrego a algun envio que ya exista
							AgregarAEnvioNuevo(itemNuevo, envio.getTienda().getId());
							System.out.println("ActualizarStock: " +itemNuevo.getArticulo().getId() + " Cantidad " + itemNuevo.getCantidad());
							adminArticulo.ActualizarStockComprometido(itemNuevo.getArticulo().getId(), itemNuevo.getCantidad());
							//Finalmente grabo el envio
							manager.merge(envio);
							//reviso los estados
							revisarEstado(envio);
						}
					}
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println(e.getMessage() + e.getStackTrace().toString());
			
		}
	}
}
